#include "../mainwindow.h"
#include "openglrenderer.h"
#include "../data/geometrydata.h"
#include "../maininterface.h"
#include "openglrendercontrol.h"
#include "../datamanager/geometrydatanode.h"

using namespace PBVP;

OpenGLRenderer::OpenGLRenderer()
:  m_Color(0, 255, 0, 255)
{
	m_WireFrame = false;
	m_Shading = GL_SMOOTH;
	m_Visible = true;
	m_ShowBBox = false;
	m_pControl = new OpenGLRenderControl(this);
}

OpenGLRenderer::~OpenGLRenderer()
{
	m_pControl->setParent(NULL);
	delete m_pControl;
}

void OpenGLRenderer::initialize(MainInterface* mainInterface)
{
	m_pMainInterface = mainInterface;
	connect(this, SIGNAL(rendererChanged()), m_pMainInterface->getMainWindow(), SLOT(updateView()));
}

RenderPlugin* OpenGLRenderer::clone()
{
	OpenGLRenderer *pRender = new OpenGLRenderer();
	pRender->m_pMainInterface = m_pMainInterface;
	pRender->m_Color = m_Color;
	return pRender;
}

bool OpenGLRenderer::initRender()
{
	return true;
}

/// This Renderer supports only geometry data
bool OpenGLRenderer::isSupported(DataInterface *pData) const
{
#ifdef __GNU__
	if(pData->getDataSetType() == GEOMETRY_DATA) return true;
#else
	GeometryData *pGeoData = dynamic_cast<GeometryData *>(pData);
	if(pGeoData) return true;
#endif
	return false;
}

void OpenGLRenderer::setDataNode(DataNode *pDataNode)
{
#ifdef __GNU__
	m_pGeoNode = (GeometryDataNode *)(pDataNode);
#else
	m_pGeoNode = dynamic_cast<GeometryDataNode *>(pDataNode);
#endif
}

void OpenGLRenderer::begin()
{
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	if (m_WireFrame)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	} else {
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	// glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
	glShadeModel(m_Shading);
	float color[4] = {m_Color.redF(), m_Color.greenF(), m_Color.blueF(), m_Color.alphaF()};
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
	if (m_Color.alpha() < 254)
	{
		glDepthMask(GL_FALSE);
	}
}

void OpenGLRenderer::end()
{
	glPopAttrib();
}

void OpenGLRenderer::reset()
{
	m_WireFrame = false;
	m_Shading = GL_SMOOTH;
}

void OpenGLRenderer::render(PBVP::DataNode *pDataNode)
{
#ifdef __GNU__
	GeometryDataNode *pGeoNode = (GeometryDataNode *)(pDataNode);
#else
	GeometryDataNode *pGeoNode = dynamic_cast<GeometryDataNode *>(pDataNode);
	if(!pGeoNode) return;	// dont draw if not a geometry data
#endif
	GeometryData *pGeoData = (GeometryData *)pGeoNode->data();

	// Don't render if not visible
	if(!m_Visible) return;

	glPushMatrix();
	if (m_ShowBBox)
	{
		pGeoNode->drawBoundingbox();
	}

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);

	glVertexPointer(3, GL_FLOAT, 0, pGeoData->vertexPointer());
	glNormalPointer(GL_FLOAT, 0, pGeoData->normalPointer());
	if(pGeoData->hasColorArray()) {
		glEnable(GL_COLOR_MATERIAL);
		glEnableClientState(GL_COLOR_ARRAY);
		glColorPointer(3, GL_FLOAT, 0, pGeoData->colorPointer());
	}
	glDrawElements(GL_TRIANGLES, 3*pGeoData->numOfTriangles(),
		GL_UNSIGNED_INT, pGeoData->triangleIndexPointer());

	glPopMatrix();
}

QWidget* OpenGLRenderer::getRenderControl() const
{
	return m_pControl;
}

//////////////////////////////////////////////////////////////////////////
// Public slots
//////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::updateView()
{
	// m_pMainInterface->getMainWindow()->updateView();
	m_pGeoNode->updateView();
}

void OpenGLRenderer::setColor(const QColor& color)
{
	m_Color = color;
	updateView();
}

void OpenGLRenderer::setTransparency(int alpha)
{
	m_Color.setAlpha(alpha);
	updateView();
}

void OpenGLRenderer::setVisible(int state)
{
	if(state == Qt::Checked) m_Visible = true;
	else m_Visible = false;
	updateView();
}

void OpenGLRenderer::showBBox(int state)
{
	if(state == Qt::Checked) m_ShowBBox = true;
	else m_ShowBBox = false;
	updateView();
}
